<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-所谓的数独</title>
    <link rel="stylesheet" href="../../reset.css">
    <style>
        li{
            list-style-type: none;
        }
        .shake {
            animation: shake-opacity 500ms 1 ease-in-out;
        }
        @keyframes shake-opacity {
            0% {
                transform: translate(0px, 0px) rotate(0deg);
                opacity: 0.6;
            }
            10% {
                transform: translate(-2px, -1px) rotate(-0.5deg);
                opacity: 0.5;
            }
            20% {
                transform: translate(-4px, 4px) rotate(1.5deg);
                opacity: 0.4;
            }
            30% {
                transform: translate(-4px, -1px) rotate(-1.5deg);
                opacity: 0.8;
            }
            40% {
                transform: translate(-2px, -1px) rotate(-2.5deg);
                opacity: 0.3;
            }
            50% {
                transform: translate(-4px, 1px) rotate(-2.5deg);
                opacity: 0.5;
            }
            60% {
                transform: translate(-2px, 4px) rotate(0.5deg);
                opacity: 0.1;
            }
            70% {
                transform: translate(-3px, 1px) rotate(-0.5deg);
                opacity: 0.4;
            }
            80% {
                transform: translate(0px, 0px) rotate(-0.5deg);
                opacity: 0.5;
            }
            90% {
                transform: translate(2px, -1px) rotate(-2.5deg);
                opacity: 0.8;
            }
        }
        .num-box {
            margin: 0 auto;
            width: 540px;
            position: relative;
        }
        .num-box .num-check {
            position: absolute;
            width: 180px;
            box-shadow: 0 0 10px 0 #000;
            left: 0;
            top: 0;
        }
        .num-box .num-check li {
            box-sizing: border-box;
            float: left;
            background: #fff;
            color: #58B7FF;
            width: 60px;
            height: 60px;
            text-align: center;
            line-height: 60px;
            font-size: 24px;
            border: 1px solid #58B7FF;
            cursor: pointer;
            transition: all .5s;
        }
        .num-box .num-check li:hover {
            color: #fff;
            background: #58B7FF;
            border: 1px solid #fff;
        }
        .num-tips{
            color: #333;
            line-height: 32px;
            font-size: 16px;
        }
        .num-table{
            position: relative;
        }
        .num-row {
            font-size: 0;
        }
        .num-row:hover .num-col, .num-row:hover .num-col.no, .num-row:hover .num-col.cur-col {
            background: #0068b7;
        }
        .num-row .num-col {
            width: 60px;
            height: 60px;
            line-height: 60px;
            float: left;
            box-sizing: border-box;
            text-align: center;
            background: #58B7FF;
            color: #fff;
            font-size: 24px;
            font-weight: bold;
            border: 1px solid #ccc;
        }
        .num-row .num-col.no {
            background: #ccc;
            border: 1px solid #fff;
        }
        .num-row .num-col.err {
            color: #ff4949;
        }
        .num-row .num-col.cur-col {
            background: #0068b7;
        }
        .num-row .num-col.cur {
            background: #fff !important;
        }
    </style>
</head>
<body>
<div class="num-box" v-show="numShow" id="num">
    <div class="num-tips">
        <p>所谓的数独：规则</p>
        <p>1.每一行数字不重复</p>
        <p>2.每一列数字不重复</p>
    </div>
    <div class="num-table" @mouseleave="hoverCol=''" :class="{'shake':isShake}">
        <!--遍历每一行-->
        <div v-for="row,index in allNum" class="num-row clear">
            <!--遍历行里面的每一列-->
            <!--
                no:被掏空数组的样式
                cur:格子被点击时触发，被点击的格子样式
                cur-col:鼠标进入的时候触发，和被点击格子同一列的格子的样式
                err：填写错误的时候触发的样式
            -->
            <div v-for="num1,indexSub in row"
                 :class="{'no':num1==='',
                 'cur':curRow===index&&indexSub===curCol,
                 'cur-col':hoverCol===indexSub,
                 'err':(optionNow.x===index&&optionNow.y===indexSub)||(optionNowInRow.x===index&&optionNowInRow.y===indexSub)||(optionNowInCol.x===index&&optionNowInCol.y===indexSub)}"
                 @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
                {{allNumText[index][indexSub]}}

            </div>
        </div>
        <!--数字键盘-->
        <div class="num-check clear" :style="{'top':(curRow+1)*60+'px','left':(curCol+1)*60+'px'}"
             v-show="checkShow">
            <ul>
                <li @click="inputText(1)">1</li>
                <li @click="inputText(2)">2</li>
                <li @click="inputText(3)">3</li>
                <li @click="inputText(4)">4</li>
                <li @click="inputText(5)">5</li>
                <li @click="inputText(6)">6</li>
                <li @click="inputText(7)">7</li>
                <li @click="inputText(8)">8</li>
                <li @click="inputText(9)">9</li>
            </ul>
        </div>
    </div>
</div>
</body>
<script src="../vue.min.js"></script>
<script>
    new Vue({
        el:'#num',
        data:{
                name: 'welcome',
                testText: '欢迎来到',
                nowIndex: 0,
                allNum: [],//数字排列
                answer: [],//所有答案的坐标点
                allNumText: [],//数字，包括输入后的数字
                curRow: '',//当前格子所在的行的索引
                curCol: '',//当前格子所在的列的索引
                checkShow: false,//数字键盘的显示
                hoverCol: '',//鼠标进去的当前列
                hoverRow: 0,//鼠标进入的当前行
                numShow: true,//数独的显示
                optionNow: {},//输入后的格子的坐标
                optionNowInRow: {},//和输入后的格子在同一行，并且同样值的格子的坐标
                optionNowInCol: {},//和输入后的格子在同一列，并且同样值的格子的坐标
                isErr: false,//是否输入错误后
                isShake: false//是否显示震动的样式
        },
        methods: {
            /**
             * @description 显示数字键盘
             * @param i1
             * @param i2
             */
            showCheck(i1, i2){
                //点击的格子是否是被掏空的格子
                if (this.allNum[i1][i2] !== '') {
                    return
                }
                //点击的格子如果是上一次点击的格子（当前格子）
                if (i1 === this.curRow && i2 === this.curCol) {
                    //隐藏数字键盘，curRow和curCol设空
                    this.checkShow = false;
                    this.curRow = '';
                    this.curCol = '';
                }
                else {
                    //隐藏数字键盘，curRow和curCol分别设置成当前的点
                    this.checkShow = true;
                    this.curRow = i1;
                    this.curCol = i2;
                }
            },
            inputText(_text){
                //*****************************检查前的初始化
                let _row = this.curRow, _col = this.curCol;
                this.curRow = '';
                this.curCol = '';
                this.isErr = false;
                this.optionNow = {
                    x: '',
                    y: '',
                }
                this.optionNowInRow = {
                    x: '',
                    y: '',
                }
                this.optionNowInCol = {
                    x: '',
                    y: '',
                }
                //*****************************检查行
                //保存当前格子的值
                this.allNumText[_row][_col] = _text;
                let rowCheck = Object.assign(this.allNumText[_row], []);
                this.checkShow = false;
                for (let i = 0, len = rowCheck.length; i < len; i++) {
                    //如果值一样，但是坐标不一样，就是填写错误
                    if (_text === rowCheck[i] && _col !== i) {
                        this.isErr = true;
                        this.isShake = true;
                        //记录当前格子的信息
                        this.optionNow = {
                            x: _row,
                            y: _col
                        }
                        //记录和当前格子同一行，以及同一个值的格子的坐标
                        this.optionNowInRow = {
                            x: _row,
                            y: i
                        }
                    }
                }
                //*****************************检查列
                let colCheck = [];
                //首先把每一行的那一列的数值保存起来
                for (let i = 0, len = this.allNumText.length; i < len; i++) {
                    colCheck.push(this.allNumText[i][_col]);
                }
                //遍历检查
                for (let i = 0, len = colCheck.length; i < len; i++) {
                    //如果值一样，但是坐标不一样，就是填写错误
                    if (_text === colCheck[i] && _row !== i) {
                        this.isErr = true;
                        this.isShake = true;
                        //记录和当前格子同一列，以及同一个值的格子的坐标
                        this.optionNowInCol = {
                            x: i,
                            y: _col
                        }
                    }
                }
                //如果发现的同样的
                if (this.isErr) {
                    setTimeout(() => {
                        this.isShake = false;
                    }, 1000)
                    return;
                }
                //如果数组去重后，长度小于9，就是行没完成
                rowCheck = rowCheck.filter(item => item !== '');
                if (rowCheck.length !== 9) {
                    console.log('行没完成')
                    return;
                }

                let coloCheck = [];
                //如果数组去重后，长度小于9，就是列没完成
                for (let i = 0, len = this.allNumText.length; i < len; i++) {
                    coloCheck = [...new Set(this.allNumText[i])];
                    coloCheck = coloCheck.filter(item => item !== '');
                    if (coloCheck.length !== 9) {
                        console.log('没完成')
                        return;
                    }
                }
                alert('挑战成功，但是没奖品');
                this.numShow = false;
            }
        },
        mounted(){
            let arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
            let row = [], rowCol = 0;
            for (let i = 0, len = arr1.length; i < len; i++) {
                row = Object.assign([], arr1);
                this.allNum.push(row);
                rowCol = arr1.splice(0, 1)[0];
                arr1.push(rowCol)
            }
            //打乱行
            this.allNum.sort((n1, n2) => Math.random() - 0.5);
            //随机获取两列的索引
            function randomText() {
                let rondomIndex = 0, rondomIndexAfter = 0;
                //获取第一列的索引
                rondomIndex = Math.floor(Math.random() * 9);
                function randomDo() {
                    rondomIndexAfter = Math.floor(Math.random() * 9);
                    //如果第一列和第二列索引一样，第二列的索引再次重新获取
                    if (rondomIndexAfter === rondomIndex) {
                        randomDo();
                    }
                }

                randomDo();
                //返回两列的索引
                return [rondomIndex, rondomIndexAfter]
            }

            //打乱列
            let randomArr = [], nowValue = 0;
            //同样遍历9次
            for (let i = 0; i < 9; i++) {
                randomArr = Object.assign([], randomText());
                //遍历每一行，给每一行的随机两列交换值
                for (let j = 0, len = this.allNum.length; j < len; j++) {
                    //随机两列交换值
                    nowValue = this.allNum[j][randomArr[0]];
                    this.allNum[j][randomArr[0]] = this.allNum[j][randomArr[1]];
                    this.allNum[j][randomArr[1]] = nowValue;
                }
            }

            //记录所有坐标
            let rowText = '', arrText = []
            for (let i = 0; i < 9; i++) {
                rowText = ''
                for (let j = 0; j < 9; j++) {
                    rowText += i + '-' + j + ',';
                }
                arrText.push(rowText.substr(0, rowText.length - 1))
            }
            console.log(arrText);
            //随机掏空
            let nowItme = [], _option, nowOption = [];
            for (let i = 0; i < 9; i++) {
                //抽取当前行的所有坐标
                nowItme = arrText[i].split(',');
                nowOption = [];
                //当前行的随机两个坐标掏空
                for (let j = 0; j < 2; j++) {
                    //抽取当前行的随机一个坐标
                    _option = Math.floor(Math.random() * nowItme.length);
                    //分割坐标的x,y
                    nowOption = nowItme.splice(_option,1)[0].split("-");
                    this.allNum[nowOption[0]][nowOption[1]] = '';
                }

            }
            //深度拷贝数独的数字
            this.allNumText = JSON.parse(JSON.stringify(this.allNum));
        }
    })
</script>
</html>